package com.bendibao.online_poster.utils;

import lombok.Data;
import sun.misc.Unsafe;

import java.lang.reflect.Field;
import java.util.concurrent.CopyOnWriteArrayList;

@Data
public class ReLock {

	public final static Unsafe unsafe;

	private volatile int state;

	private transient volatile Thread current=null;

	private CopyOnWriteArrayList<Thread> list=new CopyOnWriteArrayList<>();

	static {
		Field theUnsafe = null;
		try {
			theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
			theUnsafe.setAccessible(true);
			unsafe = (Unsafe) theUnsafe.get(null);
		} catch (NoSuchFieldException | IllegalAccessException e) {
			throw new RuntimeException(e);
		}
	}

	long offset;
	long currentOffset;
	public ReLock(){
		try {
			offset = unsafe.objectFieldOffset(ReLock.class.getDeclaredField("state"));
			currentOffset = unsafe.objectFieldOffset(ReLock.class.getDeclaredField("current"));
		} catch (NoSuchFieldException e) {
			throw new RuntimeException(e);
		}
	}

	void lock(){
		Thread thread = Thread.currentThread();
		if(thread.equals(current)){
			state++;
			return;
		}
		else if (!casThread(null,thread)) {
			list.add(thread);
			unsafe.park(false, 0);
			while (!casThread(null,thread));
		}
		while (!casState(0,1));
	}


	void unlock(){
		state--;// 可重入锁
		if(state==0) {
			casThread(current,null);
			if(!list.isEmpty()){
				Thread thread = list.get(0);
				unsafe.unpark(thread);
				list.remove(0);
			}
		}
	}

	private boolean casThread(Thread expected,Thread x ){
		return unsafe.compareAndSwapObject(this,currentOffset,expected,x);
	}

	private boolean casState(int expected,int x ){
		return unsafe.compareAndSwapInt(this,offset,expected,x);
	}

}
